﻿using System;
using System.ComponentModel;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Extensibility;

namespace BusinessFramework.AOP
{
    [Serializable]
    [MulticastAttributeUsage(MulticastTargets.Class, Inheritance = MulticastInheritance.Strict)]
    public sealed class AddNotifyPropertyChangedAttribute : InstanceLevelAspect
    {
        [ImportMember("OnPropertyChanged", IsRequired = false)]
        public Action<PropertyChangedEventArgs> OnPropertyChangedMethod;

        [ImportMember("OnPropertyChanged", IsRequired = false)]
        public Action<string> OnPropertyChangedStringMethod;

        [ImportMember("RaisePropertyChanged", IsRequired = false)]
        public Action<PropertyChangedEventArgs> RaisePropertyChangedMethod;

        [ImportMember("RaisePropertyChanged", IsRequired = false)]
        public Action<string> RaisePropertyChangedStringMethod;

        [OnLocationSetValueAdvice,
         MulticastPointcut(Targets = MulticastTargets.Property, Attributes = MulticastAttributes.Instance | MulticastAttributes.NonAbstract)]
        public void OnPropertySet(LocationInterceptionArgs args)
        {
            // Don't go further if the new value is equal to the old one.
            if (args.Value == null && args.GetCurrentValue() == null) return;
            if (args.Value != null && args.Value.Equals(args.GetCurrentValue())) return;

            // Actually sets the value.
            args.ProceedSetValue();

            if (OnPropertyChangedMethod!= null)
                OnPropertyChangedMethod(new PropertyChangedEventArgs(args.Location.Name));
            else if (OnPropertyChangedStringMethod != null)
                OnPropertyChangedStringMethod(args.Location.Name);
            else if (RaisePropertyChangedMethod != null)
                RaisePropertyChangedMethod(new PropertyChangedEventArgs(args.Location.Name));
            else if (RaisePropertyChangedStringMethod != null)
                RaisePropertyChangedStringMethod(args.Location.Name);
        }
    }
}